//************************************************************************************************************
// CoNatural.Data.dll
// Author: Roger Torres
//************************************************************************************************************
// You can use, modify, and distribute the source code and executable programs based on the source code.
// This source code is provided "as is" and without warranties as to performance or merchantability. 
// The author and/or distributors of this source code may have made statements about this source code. 
// Any such statements do not constitute warranties and shall not be relied on by the user in deciding 
// whether to use this source code. This source code is provided without any express or implied warranties 
// whatsoever. Because of the diversity of conditions and hardware under which this source code may be used, 
// no warranty of fitness for a particular purpose is offered. The user is advised to test the source code 
// thoroughly before relying on it. The user must assume the entire risk of using the source code.
//************************************************************************************************************

using System;
using System.Collections.Generic;
using System.Data;
using System.Transactions;

namespace CoNatural.Data {
	/// <summary>
	/// Share one connection in transaction scopes to favor lightweight transactions.
	/// </summary>
	internal class SharedConnection {
		private IConnection connection;
		private IList<Transaction> open_transactions;
		private IDbConnection dbconnection;

		internal SharedConnection(IConnection connection) {
			this.connection = connection;
			open_transactions = new List<Transaction>();
		}

		internal IDbConnection Open() {
			var current = Transaction.Current;
			if (current.TransactionInformation.Status == TransactionStatus.Active) {
				lock (this) {
					if (!open_transactions.Contains(current)) {
						open_transactions.Add(current);
						current.TransactionCompleted += (s, e) => {
							lock (this) {
								open_transactions.Remove(e.Transaction);
								// dispose shared connection when all transactions done.
								if (open_transactions.Count == 0) {
									if (dbconnection != null) {
										if (dbconnection.State == ConnectionState.Open)
											dbconnection.Close();
										dbconnection.Dispose();
										dbconnection = null;
									}
								}
							}
						};
					}

					if (dbconnection == null) {
						dbconnection = connection.DataBinder.DbProvider.CreateConnection();
						dbconnection.ConnectionString = connection.ConnectionString;
						dbconnection.Open();
					}
					return dbconnection;
				}
			}
			throw new Exception(string.Format("Cannot open connection in {0} transaction {1}.", 
				current.TransactionInformation.Status, 
				current.TransactionInformation.LocalIdentifier));
		}
	}
}
